﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using NUnit.Framework;
using log4net;
using log4net.Appender;
using log4net.Config;

//using log4net;
//using log4net.Config;

namespace VoteForAnna
{
    [TestFixture]
    class Program
    {
        private static readonly ILog log = LogManager.GetLogger(typeof(Program));
        public static string voteUrl = "http://www.aquatriple.by/up_vote.php";
        public static string formData = "id=4645";
        private static int timeout = 5000;
        private static int CountOfVotesPerDay = 1000;
        private static Random random = new Random();

        static void Main(string[] args)
        {

            XmlConfigurator.Configure();
            //var proxyAddress = "190.182.46.88:80";
            GetRatings();
            
			VoteWithSecondSourceOfProxies();
            VoteWithFirstSourceOfProxies();
        }

        public static void GetRatings()
        {
            var url = "http://www.aquatriple.by/interest/photo/";
            var content = Program.GetRequestContent(url);
            var pattern = @"vote_\d+"" class=""n_voted"">\d+</div>";
            var regex = new Regex(pattern);
            var kids = new List<dynamic>();
            foreach (var match in regex.Matches(content))
            {
                var m = match.ToString();
                var reg = new Regex(@"vote_\d+");
                var regVotes = new Regex(@"\d+</div>");
                kids.Add(new { Id = reg.Match(m).ToString().Replace("vote_", " "), VotesCount = Convert.ToInt32(regVotes.Match(m).ToString().Replace("</div>", "")) });

            }

            var sorted = kids.OrderByDescending(x => x.VotesCount);

            for (int i = 0; i < 5; i++ )
            {
                var kid = sorted.ElementAt(i);
                log.Info(string.Format("id {0}, votes count {1} ", kid.Id, kid.VotesCount));
            }
        }

		public static void VoteWithSecondSourceOfProxies()
		{
			var ipRegexp = @"\d+.\d+.\d+.\d+[:][\d]+"; ;
			var proxyUrl = @"http://www.cool-proxy.net/index.php?action=anonymous-proxy-list&page={0}";
			var replace = " "; // can't be empty string
			var replaceTo = " ";
			var pageCount = 14;
			var proxyList = GetListOfAllProxiesServersForSource(proxyUrl, ipRegexp, replace, replaceTo, pageCount).ToArray();
			proxyList.shuffle();
			VoteFor(voteUrl, formData, proxyList);
		}

		public static  void VoteWithFirstSourceOfProxies()
		{
			var ipRegexp = @"\d+.\d+.\d+.\d+</span></td>\t\n         <td>\n\d+";
			var proxyUrl = @"http://hidemyass.com/proxy-list/{0}";
			var replace = "</span></td>\t\n         <td>\n";
			var replaceTo = ":";
			var pageCount = 14;
			var proxyList = GetListOfAllProxiesServersForSource(proxyUrl, ipRegexp, replace, replaceTo, pageCount).ToArray();
			proxyList.shuffle();
			VoteFor(voteUrl, formData, proxyList);
		}

        public static void PopulateProxiesWithPaging(string proxyUrl, List<string> urlList, int upperBound)
        {
            Action<int> func = x => urlList.Add(string.Format(proxyUrl, x));
            for (int i = 1; i < upperBound; i++)
            {
                func(i);
            }
        }

        public static IList<string> GetListOfAllProxiesServersForSource(string proxyWebsite, string ipRegexp, string replace, string replaceTo,int pageNumber)
        {
            var proxyList = new List<string>();
          
            var urlList = new List<string>();
            
            PopulateProxiesWithPaging(proxyWebsite, urlList, pageNumber);
            foreach (var url in urlList)
            {
                {
                    {

                        string content = string.Empty;

                        {
                            content = GetRequestContent(url);

                        }

                        if (!string.IsNullOrEmpty(content))
                        {
                            var regexp = new Regex(ipRegexp);
                            foreach (var match in regexp.Matches(content))
                            {
                                //VoteFor(voteUrl, formData, match.ToString());
								proxyList.Add(match.ToString().Replace(replace, replaceTo));
                            }

                        }

                    }
                }
            }
            log.Info("Count of Items in proxy list is " + proxyList.Count);
            return proxyList;
        }




        public static string GetRequestContent(string url)
        {
            var request = WebRequest.Create(url);
            request.Timeout = timeout;
            HttpWebResponse response = null;
            Stream responseStream = null;
            try
            {
                response = (HttpWebResponse)request.GetResponse();
                log.Info("Server response status " + response.StatusDescription);
                responseStream = response.GetResponseStream();

            }
            catch (Exception ex)
            {
                log.Fatal("Failed to get content on GetResponseStream() for url " + url, ex);

            }

            if (responseStream != null)
            {
                var reader = new StreamReader(responseStream);

                var value = reader.ReadToEnd();

                response.Close();
                responseStream.Close();
                reader.Close();
                return value;

            }

            log.Fatal("Request returned nothing");
            return null;
        }

        public static void VoteFor(string voteUrl, string formData, IEnumerable<string> proxyAddresses)
        {
            foreach (var address in proxyAddresses)
            {

                if (GetCountOfVotesPerDay() < CountOfVotesPerDay)
                    VoteFor(voteUrl, formData, address);
                else
                {
                    log.Info("Count of votes per day " + CountOfVotesPerDay + " exceeded");
                }
            }
        }

        private static int GetCountOfVotesPerDay()
        {
            var appenders = LogManager.GetRepository()
                .GetAppenders();
            var rootAppender = (RollingFileAppender)appenders.First(appender => appender is RollingFileAppender);

            //var reader = new StreamReader(rootAppender.File);
            //var content = reader.ReadToEnd();
            //reader.Close();
            string content;

            var file = rootAppender.File;

            using (var reader = new StreamReader(file))
            {
                content = reader.ReadToEnd();
            }

            var time = DateTime.Now;
            var dateTime = new DateTime(time.Year, time.Month, time.Day);
            var currentDate = string.Format("{0}-{1}-{2}", dateTime.Year, dateTime.Month, dateTime.Day);
            //var currentDate = dateTime.ToShortDateString().Replace('.', '-');
            var pattern = String.Format(@"{0}.+ Vote number is \d+", currentDate);
            var template = new Regex(pattern);
            var list = new List<dynamic>();
            foreach (var match in template.Matches(content))
            {
                var input = match.ToString();
                var date = new Regex(@"^\d+-\d+-\d+").Match(input);
                var number = new Regex(@"\d+$").Match(input);
                list.Add(new { date, number });
            }

            if (list.Count > 0)
            {
                var votesNumber = Convert.ToInt32(list[list.Count - 1].number.ToString()) - Convert.ToInt32(list[0].number.ToString());
                return votesNumber;
            }
            return 0;
        }

        public static void VoteFor(string voteUrl, string formData, string proxyAddress)
        {
            log.Info("proxy address is " + proxyAddress);

            var request = WebRequest.Create(voteUrl);
            var urlString = formData;

            HttpWebResponse response = null;
            Stream responseStream = null;
            StreamReader reader = null;
            try
            {
                var proxy = new WebProxy(proxyAddress);
                request.Proxy = proxy;
                request.Method = "POST";
                request.ContentType = "application/x-www-form-urlencoded";

                request.Timeout = timeout;
                var encoding = new ASCIIEncoding();
                var data = encoding.GetBytes(urlString);
                request.ContentLength = data.Length;
                var stream = request.GetRequestStream();
                stream.Write(data, 0, data.Length);
                stream.Flush();
                stream.Close();

                response = (HttpWebResponse)request.GetResponse();
                log.Info("Server response status " + response.StatusDescription);

                responseStream = response.GetResponseStream();
                if (responseStream != null)
                {
                    reader = new StreamReader(responseStream);
                    //{
                    string value = reader.ReadToEnd();
                    log.Info("Vote number is " + value);
                    var randomNumber = random.Next(5);
                    log.Info(string.Format("Random number is {0}", randomNumber));
                    Thread.Sleep(randomNumber * 1000);
                    //}
                }
                else
                {
                    log.Fatal("Request return nothing");
                }

            }
            catch (Exception ex)
            {

                log.Fatal("Voting exception ", ex);
            }
            finally
            {
                if (responseStream != null) responseStream.Close();
                if (response != null) response.Close();
                if (reader != null) reader.Close();
            }
        }
    }
}
